// Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::path::PathBuf;

use anyhow::Context;
use clap::Parser;
use indicatif::MultiProgress;

use crate::{database::deploy_stat::DeployStats, deploy::collect_rollback_pkgs, FerriumCommand};

#[derive(Debug, Parser)]
pub struct RollbackCommand {
    /// The root path to deploy
    #[arg(long)]
    root: PathBuf,
    /// Rollback to a specific state by ID
    #[arg(long, group = "input")]
    id: Option<usize>,
    /// Rollback to last state
    #[arg(long, group = "input")]
    last: bool,
}

impl FerriumCommand for RollbackCommand {
    async fn run(self, _multi_progress: MultiProgress) -> anyhow::Result<()> {
        let root = std::path::absolute(&self.root)
            .context(format!("failed to absolute '{}'", self.root.display()))?;
        let stats_dir = DeployStats::deploy_stat_dir(&root);
        let (current_stats, current_id) = DeployStats::load_current(&stats_dir)
            .await
            .context(format!("failed to load current deploy stats in '{}'", stats_dir.display()))?
            .context(format!("no deploy stats found in '{}'", stats_dir.display()))?;
        let target_id = if self.last {
            current_id - 1
        } else if let Some(id) = self.id {
            id
        } else {
            return Err(anyhow::anyhow!("no input id"));
        };
        
        let to_rollback = collect_rollback_pkgs(&stats_dir,
            &current_stats,
            current_id,
            target_id,
        ).await?;
        crate::deploy::rollback(&root, &current_stats, to_rollback).await
            .context("failed to rollback")?;
        DeployStats::update_current_id(&stats_dir, target_id).await
            .context("failed to update current deploy stat id")?;
        Ok(())
    }
}
